/* ---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

// 部分代码来源并修改自 https://github.com/microsoft/vscode/blob/1.55.0/src/vs/workbench/contrib/terminal/common/environmentVariableCollection.ts

import { IProcessEnvironment, OperatingSystem } from '../../utils';

import {
  EnvironmentVariableMutatorType,
  IEnvironmentVariableCollection,
  IExtensionOwnedEnvironmentVariableMutator,
  IMergedEnvironmentVariableCollection,
  IMergedEnvironmentVariableCollectionDiff,
} from './environmentVariable';

// 合并后的环境变量集合实现
export class MergedEnvironmentVariableCollection
  implements IMergedEnvironmentVariableCollection
{
  // 变量名到变更器数组的映射
  readonly map: Map<string, IExtensionOwnedEnvironmentVariableMutator[]> =
    new Map();

  /**
   * 构造函数，合并所有扩展的环境变量集合
   * @param collections 所有扩展的环境变量集合
   */
  constructor(collections: Map<string, IEnvironmentVariableCollection>) {
    collections.forEach((collection, extensionIdentifier) => {
      const it = collection.map.entries();
      let next = it.next();
      while (!next.done) {
        const variable = next.value[0];
        let entry = this.map.get(variable);
        if (!entry) {
          entry = [];
          this.map.set(variable, entry);
        }

        // 如果第一个变更器是 Replace，则忽略后续变更器
        if (
          entry.length > 0 &&
          entry[0].type === EnvironmentVariableMutatorType.Replace
        ) {
          next = it.next();
          continue;
        }

        // 变更器按创建顺序逆序应用
        const mutator = next.value[1];
        entry.unshift({
          extensionIdentifier,
          value: mutator.value,
          type: mutator.type,
          options: mutator.options,
        });

        next = it.next();
      }
    });
  }

  /**
   * 应用合并后的环境变量集合到进程环境变量
   * @param env 进程环境变量对象
   * @param os 操作系统类型
   * @param variableResolver 可选，变量解析函数
   */
  async applyToProcessEnvironment(
    env: IProcessEnvironment,
    os: OperatingSystem,
    variableResolver?: (str: string) => Promise<string>
  ): Promise<void> {
    let lowerToActualVariableNames:
      | { [lowerKey: string]: string | undefined }
      | undefined;
    if (os === OperatingSystem.Windows) {
      lowerToActualVariableNames = {};
      Object.keys(env).forEach(
        (e) => (lowerToActualVariableNames![e.toLowerCase()] = e)
      );
    }
    this.map.forEach((mutators, variable) => {
      const actualVariable =
        os === OperatingSystem.Windows
          ? lowerToActualVariableNames![variable.toLowerCase()] || variable
          : variable;
      mutators.forEach(async (mutator) => {
        if (mutator.options?.applyAtProcessCreation ?? true) {
          const value = variableResolver
            ? await variableResolver(mutator.value)
            : mutator.value;
          switch (mutator.type) {
            case EnvironmentVariableMutatorType.Append:
              env[actualVariable] = (env[actualVariable] || '') + value;
              break;
            case EnvironmentVariableMutatorType.Prepend:
              env[actualVariable] = value + (env[actualVariable] || '');
              break;
            case EnvironmentVariableMutatorType.Replace:
              env[actualVariable] = value;
              break;
          }
        }
      });
    });
  }

  /**
   * 计算与另一个集合的差异
   * @param other 另一个合并集合
   * @returns 差异对象或 undefined（无差异）
   */
  diff(
    other: IMergedEnvironmentVariableCollection
  ): IMergedEnvironmentVariableCollectionDiff | undefined {
    const added: Map<string, IExtensionOwnedEnvironmentVariableMutator[]> =
      new Map();
    const changed: Map<string, IExtensionOwnedEnvironmentVariableMutator[]> =
      new Map();
    const removed: Map<string, IExtensionOwnedEnvironmentVariableMutator[]> =
      new Map();

    // 查找新增
    other.map.forEach((otherMutators, variable) => {
      const currentMutators = this.map.get(variable);
      const result = getMissingMutatorsFromArray(
        otherMutators,
        currentMutators
      );
      if (result) {
        added.set(variable, result);
      }
    });

    // 查找移除
    this.map.forEach((currentMutators, variable) => {
      const otherMutators = other.map.get(variable);
      const result = getMissingMutatorsFromArray(
        currentMutators,
        otherMutators
      );
      if (result) {
        removed.set(variable, result);
      }
    });

    // 查找变更
    this.map.forEach((currentMutators, variable) => {
      const otherMutators = other.map.get(variable);
      const result = getChangedMutatorsFromArray(
        currentMutators,
        otherMutators
      );
      if (result) {
        changed.set(variable, result);
      }
    });

    if (added.size === 0 && changed.size === 0 && removed.size === 0) {
      return undefined;
    }

    return { added, changed, removed };
  }
}

/**
 * 获取 current 中存在但 other 中不存在的变更器
 * @param current 当前变更器数组
 * @param other 另一个变更器数组
 */
function getMissingMutatorsFromArray(
  current: IExtensionOwnedEnvironmentVariableMutator[],
  other: IExtensionOwnedEnvironmentVariableMutator[] | undefined
): IExtensionOwnedEnvironmentVariableMutator[] | undefined {
  // 如果 other 不存在，则 current 全部为缺失
  if (!other) {
    return current;
  }

  // 构建 other 的扩展标识集合
  const otherMutatorExtensions = new Set<string>();
  other.forEach((m) => otherMutatorExtensions.add(m.extensionIdentifier));

  // 查找 current 中缺失于 other 的项
  const result: IExtensionOwnedEnvironmentVariableMutator[] = [];
  current.forEach((mutator) => {
    if (!otherMutatorExtensions.has(mutator.extensionIdentifier)) {
      result.push(mutator);
    }
  });

  return result.length === 0 ? undefined : result;
}

/**
 * 获取 current 和 other 中扩展标识相同但内容不同的变更器
 * @param current 当前变更器数组
 * @param other 另一个变更器数组
 */
function getChangedMutatorsFromArray(
  current: IExtensionOwnedEnvironmentVariableMutator[],
  other: IExtensionOwnedEnvironmentVariableMutator[] | undefined
): IExtensionOwnedEnvironmentVariableMutator[] | undefined {
  // 如果 other 不存在，则没有变更（已被移除）
  if (!other) {
    return undefined;
  }

  // 构建 other 的扩展标识到变更器的映射
  const otherMutatorExtensions = new Map<
    string,
    IExtensionOwnedEnvironmentVariableMutator
  >();
  other.forEach((m) => otherMutatorExtensions.set(m.extensionIdentifier, m));

  // 查找扩展标识相同但 type 或 value 不同的项
  const result: IExtensionOwnedEnvironmentVariableMutator[] = [];
  current.forEach((mutator) => {
    const otherMutator = otherMutatorExtensions.get(
      mutator.extensionIdentifier
    );
    if (
      otherMutator &&
      (mutator.type !== otherMutator.type ||
        mutator.value !== otherMutator.value)
    ) {
      // 返回新的变更器
      result.push(otherMutator);
    }
  });

  return result.length === 0 ? undefined : result;
}
